/*
 * Copyright (C) 2020 Agrui
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "gtest/gtest.h"
#include <OSMemory.h>
#include <class.h>
#include <unistd.h>
#include "CheckPoint.h"

static CheckPoint sCP;

CLASS(TestClass) {
    int mValue;
    void (*__init__)(TestClass* self);
    void (*__deinit__)(TestClass* self);
    void (*testVirtual)(TestClass* self);
};

PUBLIC_CLASS_METHOD(TestClass, testVirtual);

static void Base__init__(TestClass* self) {
    sCP.add(1);
}

static void Base__deinit__(TestClass* self) {
    sCP.add(2);
}

static void Base_testVirtual(TestClass* self) {
    sCP.add(5);
}

DEF_CLASS_METHOD(TestClass, __init__, Base__init__);
DEF_CLASS_METHOD(TestClass, __deinit__, Base__deinit__);
DEF_CLASS_METHOD(TestClass, testVirtual, Base_testVirtual);

LOAD_CLASS(TestClass) {
    SET_MEMBER(TestClass, __init__);
    SET_MEMBER(TestClass, __deinit__);
    SET_MEMBER(TestClass, testVirtual);
}



CLASS(TestChildClass) {
    INHERIT(TestClass);
    void (*__init__)(TestChildClass* self);
    void (*__deinit__)(TestChildClass* self);
    void (*testVirtual)(TestClass* self);
};

PUBLIC_CLASS_METHOD(TestChildClass, testVirtual);

static void Child__init__(TestChildClass* self) {
    sCP.add(3);
    TestClass* p = SUPER(self, TestClass);
    p->__init__(p);
}

static void Child__deinit__(TestChildClass* self) {
    sCP.add(4);
    TestClass* p = SUPER(self, TestClass);
    p->__deinit__(p);
}

static void Child_testVirtual(TestClass* self) {
    sCP.add(6);
}


DEF_CLASS_METHOD(TestChildClass, __init__, Child__init__);
DEF_CLASS_METHOD(TestChildClass, __deinit__, Child__deinit__);
DEF_CLASS_METHOD(TestChildClass, testVirtual, Child_testVirtual);

LOAD_CLASS(TestChildClass) {
    __load_class_TestClass__(SUPER(self, TestClass));
    SET_MEMBER(TestChildClass, __init__);
    SET_MEMBER(TestChildClass, __deinit__);
    SET_VIRTUAL_MEMBER(TestChildClass, TestClass, testVirtual);
}


TEST(ClassTest, newBaseClassTest) {
    int verifyData[] = {1,2};
    sCP.clean();
    sCP.setCheckPoint(&verifyData[0], ARRAY_SIZE(verifyData));

    TestClass* self= (TestClass*)newTestClass();
    deleteTestClass(self);
    ASSERT_TRUE(sCP.verify());
    sCP.clean();
}

TEST(ClassTest, newChildTest) {
    int verifyData[] = {3,1,4,2};
    sCP.clean();
    sCP.setCheckPoint(&verifyData[0], ARRAY_SIZE(verifyData));
    TestChildClass* self = (TestChildClass*)newTestChildClass();
    deleteTestChildClass(self);
    ASSERT_TRUE(sCP.verify());
    sCP.clean();
}

TEST(ClassTest, virtualTest) {
    int verifyData[] = {3,1,6,4,2};
    sCP.clean();
    sCP.setCheckPoint(&verifyData[0], ARRAY_SIZE(verifyData));
    TestChildClass* self = (TestChildClass*)newTestChildClass();
    TestClass* child = SUPER(self, TestClass);
    child->testVirtual(child);
    deleteTestChildClass(self);
    ASSERT_TRUE(sCP.verify());
    sCP.clean();
}


